package zwrapper

import (
	"time"

	"github.com/hjl/db/glog"
	zmq "github.com/pebbe/zmq4"
)

// 消息请求类型
var SEND_TYPE_REQ = "REQ"   // 请求消息的标识
var SEND_TYPE_RESP = "RESP" // 响应消息的标识

type ZWrapper interface {
	Recv(funcName, str, addr string)              // 收到普通请求消息时，调用此方法处理
	RespRecv(msgId2str, str string)               // 收到响应时，回调此函数
	RecvFail(err error)                           // 接收失败时调用（比如 socket 异常）
	ClosingAllSocks()                             // 关闭时清理资源
	GetBindAddr() string                          // 让 wrapper 获取服务端 socket 信息
	GetPeerSock(addr string) (*zmq.Socket, error) // 让 wrapper 获取对端 socket 信息
	GetBindSocket() *zmq.Socket                   // 发送时需要的目标 socket
	GetLogger() *glog.ModuleLogger                // 获取日志对象
}

// 绑定和启动服务端
func Bind(zw ZWrapper) *zmq.Socket {
	bindAddr := zw.GetBindAddr()
	socket, err1 := zmq.NewSocket(zmq.ROUTER) // 创建 ROUTER socket（服务端）
	if err1 != nil {
		zw.GetLogger().Error("Bind 函数中NewSocket失败, err:", err1)
		return nil
	}
	if err2 := socket.Bind(bindAddr); err2 != nil {
		zw.GetLogger().Error("Bind 函数中Bind失败, err:", err2)
		return nil
	}
	return socket
}

// 事件循环
func StartServ(zw ZWrapper, updateFreq, recvTimes int) {
	defer zw.ClosingAllSocks()

	dr := time.Duration(updateFreq) * time.Millisecond
	timer := time.NewTicker(dr) // 启动一个定时器驱动的“轮询”循环
	for {
		select {
		case <-timer.C: // 定时器触发，调用 update 函数处理
			update(zw, recvTimes)
		}
	}
}

// 轮询处理
func update(zw ZWrapper, recvTimes int) {
	for {
		if _, err := recv(zw); err != nil {
			zw.RecvFail(err)
			break
		}
		recvTimes--
		if recvTimes <= 0 {
			break
		}
	}
}

// 对应zmq的send,根据 send 的类型有对应数量的 partial msg
func recv(zw ZWrapper) (bool, error) {
	socket := zw.GetBindSocket()
	identity, err1 := socket.Recv(zmq.DONTWAIT)
	// 1. 读取客户端 identity，必须第一步读 ROUTER 的身份
	if err1 != nil {
		return false, nil //没有消息或出错
	}
	if len(identity) == 0 {
		return false, nil // 没有身份，忽略
	}

	// 读取消息类型，是 REQ 还是 RESP
	sendType, err2 := socket.Recv(zmq.DONTWAIT)
	if err2 != nil {
		return false, err2
	}
	if sendType == SEND_TYPE_REQ {
		// 顺序读取：msgId、funcName、参数、addr
		_, err3 := socket.Recv(zmq.DONTWAIT)
		if err3 != nil {
			return false, err3
		}

		funcName, err4 := socket.Recv(zmq.DONTWAIT)
		if err4 != nil {
			return false, err4
		}

		args_str, err5 := socket.Recv(zmq.DONTWAIT)
		if err5 != nil {
			return false, err5
		}

		//addr
		addr, err6 := socket.Recv(zmq.DONTWAIT)
		if err6 != nil {
			return false, err6
		}

		zw.Recv(funcName, args_str, addr)
	} else if sendType == SEND_TYPE_RESP {
		// 简单响应结构：仅有 msgId 和返回值
		msgId2str, err3 := socket.Recv(zmq.DONTWAIT)
		if err3 != nil {
			return false, err3
		}

		args_str, err4 := socket.Recv(zmq.DONTWAIT)
		if err4 != nil {
			return false, err4
		}
		zw.RespRecv(msgId2str, args_str)
	}

	return true, nil
}

// 发送方作为 dealer,不用发送 identity
func Send(zw ZWrapper, addr, msgId2str, funcName string, argstr string) (bool, error) {
	peerSock, err := zw.GetPeerSock(addr)
	if err != nil {
		return false, err
	}

	// 使用 multipart 分段发送(zmq.SNDMORE表示后面还有分帧)
	peerSock.Send(SEND_TYPE_REQ, zmq.SNDMORE)
	peerSock.Send(msgId2str, zmq.SNDMORE)
	peerSock.Send(funcName, zmq.SNDMORE)
	peerSock.Send(argstr, zmq.SNDMORE)
	peerSock.Send(zw.GetBindAddr(), 0) // 0表示此次发送完毕

	return true, nil
}
